
#ifndef _MEMBER_BXMLNODE_H_
#define _MEMBER_BXMLNODE_H_

#include <BMap>
#include <BXmlNode>

#define xml_member(xmlnode)	((member_BXmlNode*)((BXmlNode*)xmlnode)->_ptr)

namespace BWE
{
	class AttribPair
	{
	public:
		AttribPair()
		{

		}
		BString		name;
		BString		value;
	};
	class XmlFilter
	{
	public:
		XmlFilter(const BString& desc);

		bool operator()(BXmlNode* node) const;

		void addInfo(const BString& text);

		BString					name;
		BMap<BString, BString>	attribSet;
		BArray<BString>			includeTexts;
		BArray<BString>			excludeTexts;
	};
	class XmlFormat
	{
	public:
		inline XmlFormat()
		{
			head_prev = 0;
			head_post = 0;
			tail_prev = 0;
			tail_post = 0;
		}

		inline void fromString(const BString& text)
		{
			this->text = text;
			head_prev = 0;
			head_post = 0;
			text_prev = 0;
			text_post = 0;
			tail_prev = 0;
			tail_post = 0;

			int tail_begin = text.find("</");
			if (tail_begin < text.size())
				tail_prev = text[tail_begin - 1];

			int tail_end = text.find("/>");
			if (tail_end < text.size() && tail_end + 2 < text.size())
				tail_post = text[tail_end + 2];

			int stop = bMin(tail_begin, tail_end);

			int head_end = text.find('>', 0, stop);
			if (head_end < stop)
			{
				head_post = text[head_end + 1];
				stop = head_end;
			}

			int head_begin = text.find('<', 0, stop);
			if (head_begin < stop && head_begin > 0)
				head_prev = text[head_begin - 1];

			int text_pos = text.find('#');
			if (text_pos < text.size())
			{
				text_prev = text(text_pos - 1);
				text_post = text(text_pos + 1);
			}

			if (head_prev != '\n')
				head_prev = 0;
			if (head_post != '\n')
				head_post = 0;

			if (text_prev != '\n')
				text_prev = 0;
			if (text_post != '\n')
				text_post = 0;

			if (tail_prev != '\n')
				tail_prev = 0;
			if (tail_post != '\n')
				tail_post = 0;
		}
		inline const BString& toString()
		{
			text.clear();
			if (head_prev)
				text << "\n<>";
			if (head_post)
			{
				if (text.last() == '>')
					text << '\n';
				else
					text << ">\n";
			}
			if (tail_prev)
			{
				if (text.last() == '\n')
					text << "</";
				else
					text << "\n</";
			}
			if (tail_post)
			{
				if (text.last() == '/')
					text << ">\n";
				else
					text << "/>\n";
			}
			return text;
		}

		BString		text;
		char		head_prev;
		char		head_post;
		char		text_prev;
		char		text_post;
		char		tail_prev;
		char		tail_post;

	};
	class member_BXmlNode
	{
	public:
		member_BXmlNode(BXmlNode* xmlNode);
		~member_BXmlNode();

		BXmlNode* find(XmlFilter& filter);

		BXmlNode*				boss;
		BString					text;
		BMap<BString, BString>	attribSet;
		XmlFormat				format;
		BXmlNode*				parent;
		BArray<BXmlNodeHolder>	children;

		bool					dirty;
		BString					plainText;
	};
}

#endif
